package org.jsola.contract.service.impl;

import com.itextpdf.text.pdf.PdfReader;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.jsola.common.BeanKit;
import org.jsola.common.DateKit;
import org.jsola.common.StrKit;
import org.jsola.contract.common.ExampleKit;
import org.jsola.contract.common.FileHelper;
import org.jsola.contract.common.PdfUtil;
import org.jsola.contract.common.WkPdfHelper;
import org.jsola.contract.constant.ContractConstants;
import org.jsola.contract.core.MockMultipartFile;
import org.jsola.contract.dao.ITemplateDAO;
import org.jsola.contract.dto.TemplateAddDTO;
import org.jsola.contract.dto.TemplatePreviewDTO;
import org.jsola.contract.dto.TemplateUpdateDTO;
import org.jsola.contract.entity.CategoryDO;
import org.jsola.contract.entity.TemplateDO;
import org.jsola.contract.exception.ContractException;
import org.jsola.contract.provider.ILogProviderService;
import org.jsola.contract.query.TemplateQuery;
import org.jsola.contract.service.ICategoryService;
import org.jsola.contract.service.ISealPositionService;
import org.jsola.contract.service.ISignService;
import org.jsola.contract.service.ITemplateService;
import org.jsola.contract.vo.CategoryVO;
import org.jsola.contract.vo.TemplateListVO;
import org.jsola.contract.vo.TemplateVO;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.file.core.FileProperties;
import org.jsola.file.service.ISiteFileService;
import org.jsola.log.constant.ActionType;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 合同模板
 *
 * @author JanusMix
 */
@Slf4j
@Service("contractTemplateServiceImpl")
public class TemplateServiceImpl implements ITemplateService {

    @Autowired
    private ITemplateDAO templateDAO;

    @Autowired
    private ISealPositionService sealPositionService;

    @Autowired
    private FileProperties fileProperties;

    @Autowired
    @Lazy
    private ICategoryService categoryService;

    @Autowired
    @Lazy
    private ISignService signService;

    @Autowired
    private ISiteFileService siteFileService;

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public TemplateVO save(TemplateAddDTO templateAddDTO, TokenUser tokenUser) {
        // 转DO
        TemplateDO templateDO = templateAddDTO.to(TemplateDO.class);
        String content = templateAddDTO.getContent();
        if (StrKit.isNotEmpty(content)) {
//            content = content.replaceAll("&nbsp;", " ");
            content = HtmlUtils.htmlUnescape(content);
            templateDO.setContent(content);
        }
        String contentJson = templateAddDTO.getContentJson();
        if (StrKit.isNotEmpty(contentJson)) {
//            contentJson = contentJson.replaceAll("&nbsp;", " ");
            templateDO.setContentJson(contentJson);
        }
        String name = templateDO.getName();
        name = name.replaceAll("&nbsp;", " ");
        templateDO.setName(HtmlUtils.htmlUnescape(name));
        // 保存
        templateDO = save(templateDO, tokenUser.getSiteId(), tokenUser.getUserId());
        TemplateVO templateVO = templateDO.to(TemplateVO.class);
        CategoryDO categoryDO = categoryService.selectDOById(templateDO.getCategoryId(), tokenUser.getSiteId());
        ParamException.notNull(categoryDO, "合同类型有误，请刷新后重试");
//        try {
//            // 保存log日志
//            ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
//            if (logProviderService == null) {
//                log.error("logProviderService is null");
//                return templateVO;
//            }
//            logProviderService.log(templateDO.getName() + "由管理员" + tokenUser.getUserName() +
//                            " 新建合同模板", ActionType.SAVE.getValue(), "Template"
//                    , templateDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
//        } catch (Exception e) {
//            log.error("contract保存日志出错了", e);
//        }
        return templateVO;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int update(TemplateUpdateDTO templateUpdateDTO, TokenUser tokenUser) {
        //转DO
        TemplateDO templateDO = templateUpdateDTO.to(TemplateDO.class);
        String content = templateUpdateDTO.getContent();
        if (StrKit.isNotEmpty(content)) {
//            content = content.replaceAll("&nbsp;", " ");
            content = HtmlUtils.htmlUnescape(content);
            templateDO.setContent(content);
        }
        String contentJson = templateUpdateDTO.getContentJson();
        if (StrKit.isNotEmpty(contentJson)) {
//            contentJson = contentJson.replaceAll("&nbsp;", " ");
            templateDO.setContentJson(contentJson);
        }
        if (StrKit.isNotEmpty(content)) {
            int totalPage;
            int ran = (int) ((Math.random() * 9 + 1) * 100);
            String fileName = templateDO.getId() + "_" + DateKit.getFormatDate(new Date(), "yyyyMMddHHmmss") + ran + ".pdf";
            String filePath = fileProperties.getTempPath() + File.separator + fileName;
            // 生成PDF
            WkPdfHelper.exportPdf(filePath, content);
            // PDF文件
            byte[] bytes = FileHelper.getFileBytes(filePath);
            try {
                PdfReader pdfReader = new PdfReader(bytes);
                totalPage = pdfReader.getNumberOfPages();
                templateDO.setTotalPage(totalPage);

                // 删除生成的PDF
                File file = new File(filePath);
                file.deleteOnExit();
            } catch (IOException e) {
                log.error("合同模板转PDF出错,templateId:{},error:{}", templateDO.getId(), e.getMessage());
                throw new ParamException("合同模板转PDF出错,请联系管理员");
            }
            // 修改合同签章位置
            updateSealPage(templateDO.getId(), templateDO.getTotalPage(), tokenUser);
        } else {
            templateDO.setTotalPage(0);
        }
        String name = templateDO.getName();
        name = name.replaceAll("&nbsp;", " ");
        templateDO.setName(HtmlUtils.htmlUnescape(name));
        //根据主键更新，只更新非null值
        int updateByIdSelective = updateByIdSelective(templateDO, tokenUser.getSiteId(), tokenUser.getUserId());
        CategoryDO categoryDO = categoryService.selectDOById(templateDO.getCategoryId(), tokenUser.getSiteId());
        ParamException.notNull(categoryDO, "合同类型有误，请刷新后重试");
//        try {
//            // 保存log日志
//            ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
//            if (logProviderService == null) {
//                log.error("logProviderService is null");
//                return updateByIdSelective;
//            }
//            logProviderService.log(templateDO.getName() + "由管理员" + tokenUser.getUserName() +
//                            " 修改合同模板", ActionType.UPDATE.getValue(), "Template"
//                    , templateDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
//        } catch (Exception e) {
//            log.error("contract保存日志出错了", e);
//        }
        return updateByIdSelective;
    }

    /**
     * 修改合同模板签章位置
     *
     * @param templateId 合同模板id
     * @param totalPage  pdf总页码数
     * @param tokenUser  当前用户
     */
    private void updateSealPage(Long templateId, Integer totalPage, TokenUser tokenUser) {
        if (totalPage == null || totalPage == 0) {
            // 没有总页码数,不修改
            return;
        }
        // 对于签章位置大于pdf总页码数的,修改签章页为最大页码
        sealPositionService.updateMaxSealPage(templateId, totalPage, tokenUser);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... templateIds) {
        List<TemplateDO> templateDOList = listByIds(tokenUser.getSiteId(), (Object[]) templateIds);
        if (CollectionUtils.isEmpty(templateDOList)) {
            return templateIds.length;
        }
        int deleteByIds = deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) templateIds);
//        try {
//            for (TemplateDO templateDO : templateDOList) {
//                CategoryDO categoryDO = categoryService.selectDOById(templateDO.getCategoryId(), tokenUser.getSiteId());
//                ParamException.notNull(categoryDO, "合同类型有误，请刷新后重试");
//                // 保存log日志
//                ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
//                if (logProviderService == null) {
//                    log.error("logProviderService is null");
//                    return deleteByIds;
//                }
//                logProviderService.log(templateDO.getName() + "由管理员" + tokenUser.getUserName() +
//                                " 删除合同模板", ActionType.DELETE.getValue(), "Template"
//                        , templateDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
//            }
//        } catch (Exception e) {
//            log.error("contract保存日志出错了", e);
//        }
        return deleteByIds;
    }


    @Override
    public TemplateVO selectById(Long templateId, String siteId) {
        TemplateDO templateDO = selectDOById(templateId, siteId);
        if (templateDO == null) {
            return null;
        }
        CategoryVO category = categoryService.selectById(templateDO.getCategoryId(), siteId);
        TemplateVO result = templateDO.to(TemplateVO.class);
        if(!ObjectUtils.isEmpty(category)){
            result.setSignType(category.getSignType());
        }
        return result;
    }

    @Override
    public List<TemplateListVO> select(TemplateQuery templateQuery, String siteId) {
        List<TemplateDO> templateDOList = selectDO(templateQuery, siteId);
        if (CollectionUtils.isEmpty(templateDOList)) {
            return templateDOList == null ? null : new ArrayList<>();
        }
        return templateDOList.stream()
                .map(templateDO -> templateDO.to(TemplateListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(TemplateQuery templateQuery, String siteId) {
        Example example = buildExample(templateQuery, siteId);
        return templateDAO.selectCountByExample(example);
    }

    @Override
    public Page<TemplateListVO> selectPage(TemplateQuery templateQuery, String siteId) {
        Example example = buildExample(templateQuery, siteId);
        Page<TemplateDO> page = templateDAO.selectPageByExample(example,
                templateQuery.getPageNo(),
                templateQuery.getPageSize());

        return page.to(TemplateListVO.class);
    }

    @Override
    public TemplateDO selectDOById(Long templateId, String siteId) {
        return listById(templateId, siteId);
    }

    @Override
    public List<TemplateDO> selectDO(TemplateQuery templateQuery, String siteId) {
        Example example = buildExample(templateQuery, siteId);
        return templateDAO.selectByExample(example);
    }

    @Override
    public List<TemplateDO> selectByCategoryId(Long categoryId, String siteId) {
        ParamException.notNull(categoryId, "分类id不能为空");
        Example example = new Example(TemplateDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("categoryId", categoryId);
        example.orderBy("gmtCreate").desc();
        return templateDAO.selectByExample(example);
    }

    @Override
    public List<TemplateDO> selectByCategoryIds(List<Long> categoryIds, String siteId) {
        if (CollectionUtils.isEmpty(categoryIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(TemplateDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andIn("categoryId", categoryIds);
        return templateDAO.selectByExample(example);
    }

    @Override
    public String viewJpgPath(TemplatePreviewDTO templatePreviewDTO, TokenUser tokenUser) {
        String fileName = templatePreviewDTO.getFileName() + ".pdf";
        String filePdfPath = fileProperties.getTempPath() + File.separator + fileName;
        byte[] bytes = new byte[]{};
        //创建文件
        FileHelper.saveFileByStream(bytes, filePdfPath);
        //富文本反转义
        String content = HtmlUtils.htmlUnescape(templatePreviewDTO.getContent() == null ? " " : templatePreviewDTO.getContent());
        if (templatePreviewDTO.getReplace() != null && templatePreviewDTO.getReplace()) {
            String REG_A = "<a[^>]*?>";
            Pattern A_REG_PATTERN = Pattern.compile(REG_A, Pattern.CASE_INSENSITIVE);
            Matcher contentMatcher = A_REG_PATTERN.matcher(content);
            content = contentMatcher.replaceAll("").replaceAll("</a>", "");
        }

        if (!CollectionUtils.isEmpty(templatePreviewDTO.getVariableList())) {
            content = signService.substitutionVariable(content, templatePreviewDTO.getVariableList(), new ArrayList<>());
        }
        //文件根据内容转为pdf
        WkPdfHelper.exportPdf(filePdfPath, content);
        // 生成jpg
        String fileJpgName = System.currentTimeMillis() + ".jpg";
        String fileJpgPath = fileProperties.getTempPath() + File.separator + fileJpgName;
        File file = new File(fileJpgPath);
        PdfUtil.pdf2multiImage(filePdfPath, fileJpgPath, 80);
        MultipartFile[] multipartFilesJpg = new MultipartFile[1];
        try {
            FileInputStream fileInputStreamTwo = new FileInputStream(file);
            MultipartFile multipartFile = new MockMultipartFile("copy" + file.getName(), file.getName(),
                    ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStreamTwo);
            multipartFilesJpg[0] = multipartFile;
        } catch (IOException e) {
            e.printStackTrace();
            throw new ParamException("文件转化失败!");
        }
        List<String> downloadReport = siteFileService.uploadTemporary(multipartFilesJpg, "attachment", tokenUser);
        ContractException.isFalse(CollectionUtils.isEmpty(downloadReport), "上传文件出错了,请稍后重试或联系管理员");
        return downloadReport.get(0);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param templateQuery 查询参数
     * @param siteId        所属站点id
     * @return example
     */
    private Example buildExample(TemplateQuery templateQuery, String siteId) {
        Example example = new Example(TemplateDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (templateQuery.getName() != null) {
            example.and().andEqualTo("name", templateQuery.getName());
        }
        if (templateQuery.getCategoryId() != null) {
            example.and().andEqualTo("categoryId", templateQuery.getCategoryId());
        }
        if (templateQuery.getContent() != null) {
            example.and().andLike("content", "%" + templateQuery.getContent() + "%");
        }
        if (templateQuery.getContentJson() != null) {
            example.and().andLike("contentJson", "%" + templateQuery.getContentJson() + "%");
        }
        if (templateQuery.getTotalPage() != null) {
            example.and().andEqualTo("totalPage", templateQuery.getTotalPage());
        }
        // 排序
        ExampleKit.setExampleOrder(example, templateQuery.getOrders());
        return example;
    }
}




